package com.mdx.rest.security;

import com.mdx.rest.filter.JWTFilter;
import com.mdx.rest.handler.RestAuthorizationEntryPoint;
import com.mdx.rest.handler.RestfulAccessDeniedHandler;
import com.mdx.rest.service.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @author : jiagang
 * @date : Created in 2022/2/8 16:18
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;

    @Autowired
    private RestAuthorizationEntryPoint restAuthorizationEntryPoint;

    @Autowired
    private JWTProvider jwtProvider;

    /**
     * 使用configure(AuthenticationManagerBuilder) 添加认证
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth
//                .inMemoryAuthentication()
//                .withUser("admin") // 添加用户admin
//                .password("{noop}admin")  // 不设置密码加密
//                .roles("ADMIN", "USER")// 添加角色为admin，user
//                .and()
//                .withUser("user") // 添加用户user
//                .password("{noop}user")
//                .roles("USER")
//                .and()
//                .withUser("tmp") // 添加用户tmp
//                .password("{noop}tmp")
//                .roles(); // 没有角色

        // 使用数据库的用户名密码登录
        auth.userDetailsService(myUserDetailsService) // 设置自定义的userDetailsService
                .passwordEncoder(passwordEncoder());
    }

    /**
     * 使用configure(httpSecurity) 添加权限
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http
//                .authorizeRequests()
//                .antMatchers("/community/product/**").hasRole("USER") //添加/product/** 下的所有请求只能由user角色才能访问
//                .antMatchers("/community/admin/**").hasRole("ADMIN") //添加/admin/** 下的所有请求只能由admin角色才能访问
//                .anyRequest().authenticated() // 没有定义的请求，所有的角色都可以访问（tmp也可以）。
//                .and()
//                .formLogin().and() // 打开过滤器 formLogin对应着你form表单认证方式，即UsernamePasswordAuthenticationFilter
//                .httpBasic(); // 打开过滤器 httpBasic对应着Basic认证方式，即BasicAuthenticationFilter

//        http
//                .sessionManagement()
//                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)//设置无状态
//                .and()
//                .authorizeRequests() // 配置请求权限
//                .antMatchers("/community/product/**").hasRole("USER") // 需要角色
//                .antMatchers("/community/admin/**").hasRole("ADMIN")
//                .anyRequest().authenticated() // 所有的请求都需要登录
//                .and()
//                .formLogin().loginProcessingUrl("/community/login")// 配置登录url，和登录成功处理器
//                .and().exceptionHandling()
//                .accessDeniedHandler(restfulAccessDeniedHandler) // 添加自定义未授权和未登录结果返回
//                .authenticationEntryPoint(restAuthorizationEntryPoint)
//                .and().csrf().disable()// 取消csrf防护
//                .httpBasic()
//                .and()
//                .addFilterBefore(jwtFilter(),UsernamePasswordAuthenticationFilter.class); // 添加jwt 登录授权过滤器

        //使用JWT，不需要csrf
        http.csrf()
                .disable()
                //基于token，不需要session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                //所有请求都要求认证
                .anyRequest()
                .authenticated()
                //动态权限配置
                .and()
                //禁用缓存
                .headers()
                .cacheControl();
        //添加jwt 登录授权过滤器
        http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        http.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthorizationEntryPoint);


    }

    @Bean
    public JWTFilter jwtFilter() {
        return new JWTFilter();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
//        return NoOpPasswordEncoder.getInstance(); // 不使用加密算法保持密码
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(WebSecurity web) {
        // 添加不做权限的URL
        web.ignoring().antMatchers(
//                "/**/**",
                "/community/login",
                "/logout",
                "/css/**",
                "/js/**",
                "/index.html",
                "favicon.ico",
                "/doc.html",
                "/webjars/**",
                "/swagger-resources/**",
                "/v2/api-docs/**",
                "/captcha",
                "/ws/**",
                "/system/cfg/menu",
                "/api/**",
                "/community/user/info"
        );
    }

    // 加密算法
    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String password = bCryptPasswordEncoder.encode("user");
        String password2 = bCryptPasswordEncoder.encode("admin");
        System.out.println(password);
        System.out.println(password2);
    }
}
